# coding=utf-8
"""
Created on 2010-8-7

@author: morningbzy
"""
from online_user import OnlineUser
from online_user import OnlineUserList
from sgs.sgs_game import game
from sgs.common.game_action import IGameAction
from sgs.card.tao import Tao
from response import CommandListResponse
from sgs.common.constants import roleType, userState

class SGSPlayer(OnlineUser, IGameAction):
    def __init__(self, u_id, name):
        self.game = game
        OnlineUser.__init__(self, u_id, name)
        self.alive = True
        self.figures = []
        self.skillList = {}
        self.hp, self.maxHp = 0, 0
        self.shaTimes, self.maxShaTimes = 0, 0
        self.incsDist, self.descDist = 0, 0
        self.cardList = {}
        self.judgeCards = []
        self.equipCardList = []
        self.role = None
        self.deskId = None
        self.state = None

    def setFigure(self, cond, figure):
        self.figures.append(figure)
        figure.setOwner(self)
        for skill in figure.skillList:
            skillId = len(self.skillList)
            self.skillList.update({skillId: skill})
            self.addCmd('SET_SKILL', [self.deskId, skillId, skill.name])
        self.changeHp(cond, figure.hp, figure.hp)

    def changeHp(self, cond, changeHp, changeMaxHp=0):
        self.maxHp += changeMaxHp
        if self.hp + changeHp <= self.maxHp:
            self.hp += changeHp
            self.addCmd('SET_HP', [self.deskId, self.hp])

    def requireCmd(self, cond, reqCmd, args=[], respCmds=None):
        cond.acquire()
        self.addCmd(reqCmd, args)
        game.eventStack.append(cond)
        cond.wait(self.deskId, respCmds)
        resp = game.respStack.pop()
        return resp['cmd'], resp['args'][1:]

    def hasRoundBeginSkill(self):
        return False

    def hasRoundEndSkill(self):
        return False

    def callGameAction(self, method, cond, *args, **kw):
        rtn = None
        for figure in self.figures:
            if rtn:
                break
            rtn = getattr(figure, method)(cond, *args, **kw)
        return rtn or getattr(self, method)(cond, *args, **kw)

    def roundBegin(self, cond):
        print '==%s ROUND BEGIN' % self.name
        if self.hasRoundBeginSkill():
            self.addCmd('ROUND_BEGIN')
        if self.shaTimes < 1:
            self.shaTimes = 1

    def judgeBegin(self, cond):
        print '==%s JUDGE BEGIN' % self.name
        if self.judgeCards:
            self.addCmd('JUDGE_BEGIN', game.cardList.popCards(1)[0].toArray())

    def fetchBegin(self, cond):
        print '==%s FETCH BEGIN' % self.name
        self.addCards(game.cardList.popCards(2))

    def actionBegin(self, cond):
        #self.addCmd('ACTION_BEGIN')
        print '==%s ACTION BEGIN' % self.name
        self.state = userState.ROUND_BEGIN
        while True:
            cmd, args = self.requireCmd(cond, 'REQ_ACTION',
                    ['轮到你出牌了'], ['USE_SKILL', 'USE_CARD', 'CANCEL'])
            if cmd == 'CANCEL':
                break
            elif cmd == 'USE_SKILL':
                # USE_SKILL deskId skillId cardList destList
                print "DEBUG-SKILL-----------BEGIN----------"
                print args
                self.skillList[int(args[0])].action(cond, self, args)
                print "DEBUG-SKILL-----------END------------"
            elif cmd == 'USE_CARD':
                print "DEBUG-CARD-----------BEGIN----------"
                game.cardList.get(args[0]).action(cond, self, args[1:])
                print "DEBUG-CARD-----------END------------"
            else:
                assert True, 'should not return cmd ' + cmd

    def throwBegin(self, cond):
        print '==%s THROW BEGIN' % self.name
        self.state = userState.THROW_BEGIN
        while len(self.cardList) > self.hp:
            cards, _ = self.requireCard(cond, msg='请选择要弃的牌',
                    condition={'req_num': len(self.cardList) - self.hp},
                    target=False)
            for card in cards:
                if card:
                    self.removeCard(card.id)

    def roundEnd(self, cond):
        print '==%s ROUND END' % self.name
        self.state = userState.ROUND_END
        if self.hasRoundEndSkill():
            self.addCmd('ROUND_END')

    def useSha(self, cond, targetDeskId):
        #TODO: It's inelegant to return target user for this function
        #But a card instance can't get it by deskId
        if self.shaTimes == 0:
            self.addCmd('BROKE_RULE', ['本轮你杀气已尽，干点别的吧'])
            return None
        if game.users.getUserDist(self.deskId, targetDeskId) > 1:
            self.addCmd('BROKE_ROLE', ['鞭长莫及啊'])
            return None
        self.shaTimes -= 1
        return game.users.getUser(targetDeskId)

    def beSha(self, cond, src):
        # weapon
        pass

    def useShan(self, cond, dest):
        # weapon
        pass

    def beShan(self, cond, src):
        # weapon
        pass

    def useTao(self, cond, dest):
        pass

    def beTao(self, cond, src):
        self.changeHp(cond, 1)

    def beDamage(self, cond, src, srcCard, changeHp):
        self.changeHp(cond, changeHp)
        while self.hp < 1: #have Tao of self
            if not self.hasCard({'class':Tao}): break
            card = self.requireCard(cond, {'class':Tao}, '你要挂了，有桃赶紧吃吧')[0]
            if not card:
                break
            self.removeCard(card.id)
            self.beTao(cond, self)
        if self.hp < 1: #Beg Tao from others
            result = game.reqSomeoneCard(cond, Tao, self, self.deskId,
                                         num=1-self.hp, msg='%s向你求桃' % self.name)
            for owner, card in result.iteritems():
                owner.removeCard(card.id)
                self.beTao(cond, src)
        if self.hp <= 0:
            self.die(cond)

        for fig in self.figures:
            fig.beDamage(cond, src, srcCard, changeHp)

    def die(self, cond):
        assert self.hp <= 0, 'I have hp = %s, it is not fair to die' % self.hp
        self.alive = False
        for user in game.users.getAllPlayers():
            user.addCmd('DIE', [self.deskId])
            if user.deskId != self.deskId:
                user.addCmd('SHOW_OTHERS_ROLE', [self.deskId, self.role])

    def requireCard(self, cond, condition={}, msg='', target=True):
        reqCmd = target and 'REQ_CARD_TARGET' or 'REQ_CARD'
        cmd, args = self.requireCmd(cond, reqCmd, [msg], ['USE_CARD', 'CANCEL'])
        if cmd == 'CANCEL':
            return []
        elif cmd == 'USE_CARD':
            req_num = condition.get('req_num', 1)
            i = 0
            cards = []
            for cardId in args:
                if i >= req_num:
                    break
                i += 1
                if not cardId:
                    continue
                card = game.cardList.get(int(cardId))
                err = card.matchCond(condition)
                if err:
                    self.addCmd('BROKE_RULE', [err])
                    return []
                else:
                    cards.append(card)
            return cards, args[i:]
        else:
            assert True, 'should not return cmd ' + cmd

    def addCards(self, cards):
        for card in cards:
            card.onGot(self)
            self.cardList.update({card.id: card})
        cardsStrs = [c.toArray() for c in cards]
        self.addCmd('DISPATCH_CARD', cardsStrs)

    def removeCard(self, cardId, toTrash=True):
        game.cardList.get(cardId).onLost(self)
        if(toTrash):
            game.cardList.trashCard(cardId)
        self.cardList.pop(cardId)
        self.addCmd('REMOVE_CARD', [cardId])

    def equipCard(self, card):
        pass

    def hasCard(self, condition={}):
        for card in self.cardList.values():
            if not card.matchCond(condition):
                return True


class SGSPlayerList(OnlineUserList):
    def __init__(self):
        super(SGSPlayerList, self).__init__()
        self.players = [None]*8
        self.playerNum = 0
        self.role2Desks = {
            roleType.ZG: [],
            roleType.ZC: [],
            roleType.FZ: [],
            roleType.NJ: []
        }

    def checkAllFigured(self):
        for user in self.players:
            if user and not user.figures:
                return False
        return True

    def newUser(self, uId, name):
        return SGSPlayer(uId, name)

    def add(self, user):
        super(SGSPlayerList, self).add(user.id, user)
        user.deskId = self.playerNum
        self.players[self.playerNum] = user
        self.playerNum += 1

    def setDeskRole(self, deskId, role):
        self.role2Desks[role].append(deskId)

    def getUser(self, deskId):
        if deskId < len(self.players):
            return self.players[deskId]
        return None

    def getAllPlayers(self):
        return [self.players[i] for i in range(8) if self.players[i]]

    def getAlivePlayers(self):
        return [self.players[i] for i in range(8) if self.players[i]
                and self.players[i].alive]

    def getRoundDeskList(self, lastStarter):
        aliveDesks = [p.deskId for p in self.getAlivePlayers()]
        print aliveDesks
        assert len(aliveDesks) > 1, 'Less than 2 players left but game not ended'
        if lastStarter == -1:
            for i in aliveDesks:
                if self.getUser(i).role == roleType.ZG:
                    fromDesk = i
                    break
        else:
            for i in aliveDesks:
                if i >= lastStarter:
                    fromDesk = i % len(aliveDesks)
                    break
        rtn = aliveDesks[fromDesk:] + aliveDesks[:fromDesk]
        return rtn

    def getUserDist(self, fromDeskId, toDeskId):
        clockwiseDist = 0
        curDesk = fromDeskId
        while curDesk != toDeskId:
            clockwiseDist += 1
            curDesk = (curDesk+1) % self.playerNum
            assert curDesk != fromDeskId, 'Non exist desk: '+toDeskId
        antiClockwiseDisk = 0
        curDesk = fromDeskId
        while curDesk != toDeskId:
            antiClockwiseDisk += 1
            curDesk = (curDesk-1+self.playerNum) % self.playerNum
            assert curDesk != fromDeskId, 'Non exist desk: '+toDeskId
        dist = clockwiseDist if clockwiseDist < antiClockwiseDisk else antiClockwiseDisk
        dist -= self.getUser(fromDeskId).descDist
        dist += self.getUser(toDeskId).incsDist
        return dist

    def _render_GET(self, request):
        deskId = int(request.args['deskId'][0])
        cmd = self.getUser(deskId).getCmd()
        cmdList = []
        cmdList.insert(0, cmd)
        print '>>>From %d: %s' % (deskId, cmd)
        return CommandListResponse(cmdList)
